
#include <BFont>
#include <BWidget>
#include <BImage>
#include <BLayout>
#include <BStyle>

#include "IFormula.h"
#include "member_BLongSpinBox.h"

using namespace BWE;

member_BLongSpinBox::member_BLongSpinBox(BLongSpinBox* spinbox)
{
	boss = spinbox;
	value = 0;
	step = 1;
	upButton = 0;
	downButton = 0;
	align =Align_LeftCenter;
	blinkTime = 1;
	blinkTick = 0;
	hoverIndex = -1;
	prefixAlign = Align_RightCenter;
	suffixAlign = Align_LeftCenter;
	prefixStyle = 0;
	suffixStyle = 0;
	lineWidth = 1.0f;

	readOnly = false;
	formulable = false;
	blinkShown = false;
	wheelEnabled = false;
	dirtySize = true;

	block.text.reset(value);
	block.reset();
	dirty = true;
	editing = false;
	hovered = false;
	pressed = false;
}
member_BLongSpinBox::~member_BLongSpinBox()
{

}

bool member_BLongSpinBox::freshSizes()
{
	const BFont* font = boss->realFont();

	const BStyle* style = boss->realStyle();
	if (prefixStyle)
		prefixStyle->translate(prefix, t_prefix);
	else
		style->translate(prefix, t_prefix);

	if (suffixStyle)
		suffixStyle->translate(suffix, t_suffix);
	else
		style->translate(suffix, t_suffix);

	prefixSize.reset();
	if (prefix.size())
	{
		if (t_prefix.size())
			prefixSize = font->textSize(t_prefix);
		else
			prefixSize = font->textSize(prefix);
	}
	suffixSize.reset();
	if (suffix.size())
	{
		if (t_suffix.size())
			suffixSize = font->textSize(t_suffix);
		else
			suffixSize = font->textSize(suffix);
	}
	return true;
}
bool member_BLongSpinBox::freshRects()
{
	const BFont* font = boss->realFont();
	if (!font)
		return false;

	if (upButton)
	{
		int upWidth = upButton->sizeHint().width();
		int downWidth = downButton->sizeHint().width();
		int buttonWidth = bMax(upWidth, downWidth);
		boss->setPerch(Part_Right, buttonWidth);
	}

	BRect crect = boss->centerRect();
	textArea = crect;
	textArea.left() += prefixSize.width();
	textArea.right() -= suffixSize.width();

	if (block.dirty)
	{
		block.adjust(0);
	}
	BRect textRect = textArea.align(align, block.textSize);
	block.rect = textRect;

	BRect prefixArea = crect;
	prefixArea.right() = block.rect.left();
	prefixRect = prefixArea.align(prefixAlign, prefixSize);

	BRect suffixArea = crect;
	suffixArea.left() = block.rect.right();
	suffixRect = suffixArea.align(suffixAlign, suffixSize);

	if (upButton)
	{
		BRect rightRect = boss->rect(Part_Right);
		int h = rightRect.height() / 2;
		BRect upRect(rightRect.x(), rightRect.y(), rightRect.width(), h);
		upButton->setRect(upRect);
		BRect downRect(rightRect.x(), rightRect.bottom() - h, rightRect.width(), h);
		downButton->setRect(downRect);
	}
	return true;
}
BLine2 member_BLongSpinBox::inputLine()
{
	BLine2 line;
	if (block.cells.check(block.index))
	{
		BRect cellRect = block.cells[block.index].rect + block.rect.pos();
		line.setBegin(cellRect.left(), block.rect.top());
		line.setEnd(cellRect.left(), block.rect.bottom());

	}
	else
	{
		BRect cellRect = block.cells.last().rect + block.rect.pos();
		line.setBegin(cellRect.right(), block.rect.top());
		line.setEnd(cellRect.right(), block.rect.bottom());
	}
	if (!textArea.contain(line.begin()))
	{
		BPoint point = textArea.wrap(line.begin());
		BPoint offset = point - line.begin();
		block.rect.move(offset.x(), 0);
		line.move(offset.x(), 0);
	}
	return line;
}
void member_BLongSpinBox::textEdited()
{
	if (formulable)
	{
		IFormula<BLong> formula;
		BLong result = formula(block.text);
		if (!formula.error())
		{
			result = range.limit(result);
			if (value != result)
			{
				value = result;
				boss->emit(Signal_ValueChanged, value);
				boss->emit(Signal_ValueEdited, value);
			}
		}
		editing = true;
		dirty = true;
		boss->fresh();
	}
	else
	{
		BLong result = block.text.toLong();
		result = range.limit(result);
		if (value != result)
		{
			value = result;
			boss->emit(Signal_ValueChanged, value);
			boss->emit(Signal_ValueEdited, value);
		}
		dirty = true;
		editing = true;
		boss->fresh();
	}
}

void member_BLongSpinBox::slotButtonClicked(BObject* object)
{
	if (object == upButton)
	{
		if (boss->setValue(value + step))
		{
			boss->emit(Signal_ValueEdited, value);
			boss->emit(Signal_EditFinished, value);
		}
		return;
	}
	if (object == downButton)
	{
		if (boss->setValue(value - step))
		{
			boss->emit(Signal_ValueEdited, value);
			boss->emit(Signal_EditFinished, value);
		}
		return;
	}
}
